# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/12 15:38:36-07:00 yanmin.zhang@intel.com 
#   [IA64] clean up ptrace corner cases
#   
#   Patch from yanmin.zhang@intel.com to fix up some corner cases
#   in ptrace.  Many thanks to davidm for reviewing and improving.
#   
#   Backported to 2.4 by Bjorn Helgaas (bjorn.helgaas@hp.com).
# 
# arch/ia64/kernel/process.c
#   2005/03/12 15:24:43-07:00 yanmin.zhang@intel.com +1 -1
#   clean up ptrace corner cases
# 
# arch/ia64/kernel/ivt.S
#   2005/03/12 15:24:43-07:00 yanmin.zhang@intel.com +25 -22
#   clean up ptrace corner cases
# 
# arch/ia64/kernel/entry.S
#   2005/03/12 15:24:43-07:00 yanmin.zhang@intel.com +19 -7
#   clean up ptrace corner cases
# 
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S	2005-03-12 15:59:49 -08:00
+++ b/arch/ia64/kernel/entry.S	2005-03-12 15:59:49 -08:00
@@ -49,8 +49,11 @@
 	 * setup a null register window frame.
 	 */
 ENTRY(ia64_execve)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)
-	alloc loc1=ar.pfs,3,2,4,0
+	/*
+	 * Allocate 8 input registers since ptrace() may clobber them
+	 */
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc loc1=ar.pfs,8,2,4,0
 	/* Leave from kernel and restore all pt_regs to correspending registers. This is special 
 	 * because ia32 application needs scratch registers after return from execve.
 	 */
@@ -94,8 +97,11 @@
 END(ia64_execve)
 
 GLOBAL_ENTRY(sys_clone2)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
-	alloc r16=ar.pfs,3,2,4,0
+	/*
+	 * Allocate 8 input registers since ptrace() may clobber them
+	 */
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc r16=ar.pfs,8,2,4,0
 	DO_SAVE_SWITCH_STACK
 	mov loc0=rp
 	mov loc1=r16				// save ar.pfs across do_fork
@@ -113,8 +119,11 @@
 END(sys_clone2)
 
 GLOBAL_ENTRY(sys_clone)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
-	alloc r16=ar.pfs,2,2,4,0
+	/*
+	 * Allocate 8 input registers since ptrace() may clobber them
+	 */
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc r16=ar.pfs,8,2,4,0
 	DO_SAVE_SWITCH_STACK
 	mov loc0=rp
 	mov loc1=r16				// save ar.pfs across do_fork
@@ -1091,7 +1100,10 @@
 
 ENTRY(sys_rt_sigreturn)
 	PT_REGS_UNWIND_INFO(0)
-	alloc r2=ar.pfs,0,0,1,0
+	/*
+	 * Allocate 8 input registers since ptrace() may clobber them
+	 */
+	alloc r2=ar.pfs,8,0,1,0
 	.prologue
 	PT_REGS_SAVES(16)
 	adds sp=-16,sp
diff -Nru a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
--- a/arch/ia64/kernel/ivt.S	2005-03-12 15:59:49 -08:00
+++ b/arch/ia64/kernel/ivt.S	2005-03-12 15:59:49 -08:00
@@ -48,6 +48,7 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include <asm/errno.h>
 
 #if 1
 # define PSR_DEFAULT_BITS	psr.ac
@@ -678,15 +679,29 @@
 	mov r1=IA64_KR(CURRENT);		/* r1 = current (physical) */
 	;;
 	invala;
+
+	/* adjust return address so we skip over the break instruction: */
+
+	extr.u r8=r29,41,2			// extract ei field from cr.ipsr
 	extr.u r16=r29,32,2;			/* extract psr.cpl */
 	;;
+	cmp.eq p6,p7=2,r8			// isr.ei==2?
 	cmp.eq pKern,pUser=r0,r16;		/* are we in kernel mode already? (psr.cpl==0) */
-	/* switch from user to kernel RBS: */
 	;;
+(p6)	mov r8=0				// clear ei to 0
+(p6)	adds r28=16,r28				// switch cr.iip to next bundle cr.ipsr.ei wrapped
+(p7)	adds r8=1,r8				// increment ei to next slot
+	;;
+	dep r29=r8,r29,41,2			// insert new ei into cr.ipsr
+	;;
+
+	/* switch from user to kernel RBS: */
 	mov r30=r0
 	MINSTATE_START_SAVE_MIN_VIRT
 	br.call.sptk.many b7=ia64_syscall_setup
 	;;
+	// p10==true means out registers are more than 8 or r15's Nat is true
+(p10)	br.cond.spnt.many ia64_ret_from_syscall
 	mov r3=255
 	adds r15=-1024,r15			// r15 contains the syscall number---subtract 1024
 	adds r2=IA64_TASK_PTRACE_OFFSET,r13	// r2 = &current->ptrace
@@ -704,28 +719,9 @@
 	ld8 r2=[r2]				// r2 = current->ptrace
 	mov b6=r16
 
-	// arrange things so we skip over break instruction when returning:
-
-	adds r16=PT(CR_IPSR)+16,sp			// get pointer to cr_ipsr
-	adds r17=PT(CR_IIP)+16,sp			// get pointer to cr_iip
 	;;
-	ld8 r18=[r16]				// fetch cr_ipsr
 	tbit.z p8,p0=r2,PT_TRACESYS_BIT		// (current->ptrace & PF_TRACESYS) == 0?
 	;;
-	ld8 r19=[r17]				// fetch cr_iip
-	extr.u r20=r18,41,2			// extract ei field
-	;;
-	cmp.eq p6,p7=2,r20			// isr.ei==2?
-	adds r19=16,r19				// compute address of next bundle
-	;;
-(p6)	mov r20=0				// clear ei to 0
-(p7)	adds r20=1,r20				// increment ei to next slot
-	;;
-(p6)	st8 [r17]=r19				// store new cr.iip if cr.isr.ei wrapped around
-	dep r18=r20,r18,41,2			// insert new ei into cr.isr
-	;;
-	st8 [r16]=r18				// store new value for cr.isr
-
 (p8)	br.call.sptk.many b6=b6			// ignore this return addr
 
 	br.cond.sptk ia64_trace_syscall
@@ -807,8 +803,11 @@
 	 *	- psr.ic enabled, interrupts restored
 	 *	-  r1: kernel's gp
 	 *	-  r3: preserved (same as on entry)
+	 *	-  r8: -EINVAL if p10 is true
 	 *	- r12: points to kernel stack
 	 *	- r13: points to current task
+	 *	- p10: TRUE if syscall is invoked with more than 8 out
+	 *	       registers or r15's Nat is true
 	 *	- p15: TRUE if interrupts need to be re-enabled
 	 *	- ar.fpsr: set to kernel settings
 	 */
@@ -825,12 +824,15 @@
 	st8 [r17]=r28,16;	/* save cr.iip */
 	mov r28=b0;                   
 (pKern) mov r18=r0;             /* make sure r18 isn't NaT */
+	extr.u r11=r19,7,7	/* get sol of ar.pfs */
+	and r8=0x7f,r19		/* get sof of ar.pfs */
 	;;
 (p9)	mov in1=-1
 	tnat.nz p10,p0=in2
 	st8 [r16]=r30,16;	/* save cr.ifs */
 	st8 [r17]=r25,16;	/* save ar.unat */
 (pUser) sub r18=r18,r22;	/* r18=RSE.ndirty*8 */
+	add r11=8,r11
 	;;
 	st8 [r16]=r26,16;	/* save ar.pfs */
 	st8 [r17]=r27,16;	/* save ar.rsc */
@@ -870,12 +872,13 @@
 .mem.offset 8,0;                st8.spill [r17]=r15,16;
 	adds r12=-16,r1;        /* switch to kernel memory stack (with 16 bytes of scratch) */
 	;;
+	cmp.lt p10,p9=r11,r8	/* frame size can't be more than local+8 */
 	mov r13=IA64_KR(CURRENT);       /* establish `current' */
 	movl r1=__gp;           /* establish kernel global pointer */
 	;;
 	MINSTATE_END_SAVE_MIN_VIRT
 
-	tnat.nz p9,p0=r15
+(p9)	tnat.nz p10,p0=r15
 (p8)	mov in7=-1
 	ssm psr.ic | PSR_DEFAULT_BITS
 	movl r17=FPSR_DEFAULT
@@ -883,10 +886,10 @@
 	;;
 	srlz.i					// guarantee that interruption collection is on
 	cmp.eq pSys,pNonSys=r0,r0		// set pSys=1, pNonSys=0
-(p9)	mov r15=-1
 (p15)	ssm psr.i		// restore psr.i
 	mov.m ar.fpsr=r17
 	stf8 [r8]=f1            // ensure pt_regs.r8 != 0 (see handle_syscall_error)
+(p10)	mov r8=-EINVAL
 	br.ret.sptk.many b7
 END(ia64_syscall_setup)
 
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	2005-03-12 15:59:49 -08:00
+++ b/arch/ia64/kernel/process.c	2005-03-12 15:59:49 -08:00
@@ -485,7 +485,7 @@
 	return 1;	/* f0-f31 are always valid so we always return 1 */
 }
 
-asmlinkage long
+long
 sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs)
 {
 	int error;